package jp.oesf.xmldomsample;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import jp.oesf.xmldomsample.model.RowModel;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.util.Log;
import android.util.Xml;

public class XmlHelper {
	private static String TAG = "XmlHelper";
	private static XmlHelper xmlHelper = new XmlHelper();//

	/**
	 * This class is singleton.
	 */
	private XmlHelper() {
	}

	/**
	 * インスタンスの取得。
	 * 
	 * @return このクラスのインスタンス
	 */
	public static XmlHelper getInstance() {
		
		return xmlHelper;
	}

	public RowModel parseDom(Context context, String xml) {

		// RowModel row = new RowModel();
		RowModel rowModel = new RowModel();
		InputStream in = null;
		try {
			// TODO 【DOM】 No.01 ドキュメントビルダーファクトリを生成
			DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			// TODO 【DOM】 No.02 ドキュメントビルダーを生成
			DocumentBuilder builder = dbfactory.newDocumentBuilder();
			// xmlファイルのストリームを取得
			in = context.getAssets().open("sample.xml");

			Element root = null;

			// TODO 【DOM】 No.03 パースを実行してDocumentオブジェクトを取得
			Document doc = builder.parse(in);

			// TODO 【DOM】 No.04 ルート要素を取得（タグ名：root）
			root = doc.getDocumentElement();
			
			// <entry>を取得
			NodeList entryList = root.getElementsByTagName("entry");
			// 最初の<entry>を取得
			Element entryElement = (Element) entryList.item(0);

			/* <id>の処理 */
			String id = null;
			
			// TODO 【DOM】 No.05 取得した<entry>から<id>を取得
			Element idElement = (Element)entryElement.getFirstChild();
			// TODO 【DOM】 No.06 取得した<id>からTextデータを取得
			id = idElement.getFirstChild().getNodeValue();

			// 値をRowModelにセット
			rowModel.setId(id);

			/* <description>の処理 */
			// 取得した<entry>から<description>を取得
			NodeList desriptionList = entryElement
					.getElementsByTagName("description");

			// Nodeからテキスト情報を取得。
			String summary = desriptionList.item(0).getFirstChild()
					.getNodeValue();
			// 20文字以降をカットする。
			if (summary != null && 0 < summary.length()) {
				if (20 < summary.length()) {
					summary = summary.substring(0, 20);
				}
			}
			// 値をRowModelにセット
			rowModel.setSummary(summary);

			/* <thumbnail>の処理 */
			// <thumbnail>を取得
			NodeList thumbnailList = entryElement
					.getElementsByTagName("thumbnail");
			// 最初の<thumbnail>を取得
			Element thumbnailElement = (Element) thumbnailList.item(0);

			// TODO 【DOM】 No.07 <thumbnail>から"url"属性の値を取得
			String thumbnail = thumbnailElement.getAttribute("url");
			
			// 値をRowModelにセット
			rowModel.setThumbnailImageURL(thumbnail);

			/* <title>の処理 */
			// <title>を取得
			NodeList titleList = entryElement.getElementsByTagName("title");
			// Nodeからテキスト情報を取得
			String title = titleList.item(0).getFirstChild().getNodeValue();
			// 値をRowModelにセット
			rowModel.setTitle(title);

		} catch (Exception e) {
			Log.e(TAG, Log.getStackTraceString(e));
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return rowModel;
	}

	public RowModel parseSax(Context context, String xml) {
		// RowModel rowModel = null;
		InputStream is = null;
		try {
			// 解析対象のストリームを取得する
			is = context.getAssets().open("sample.xml");
			// パーサのFactoryを作成
			SAXParserFactory saxParaser = SAXParserFactory.newInstance();

			SaxHandler sh = null;
			// TODO 【SAX】 No.05  パーサを取得
			SAXParser sp = saxParaser.newSAXParser();
			// TODO 【SAX】 No.06 イベントハンドラを作成
			sh = new SaxHandler();
			// TODO 【SAX】 No.07 イベントハンドラに入力データとイベントハンドラを渡す
			sp.parse(is, sh);
			return sh.rowModel;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	class SaxHandler extends DefaultHandler {

		RowModel rowModel = new RowModel();
		
		//タグ開始フラグ
		boolean isEntry;
		boolean isId = false;
		boolean isSummary = false;
		boolean isTitle = false;
		boolean isThumbnail = false;
		String id = null;
		String summary = null;
		String thumbnail = null;
		String title = null;
		
		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			
			//TODO 【SAX】 No.01 entryタグの場合はisEntryをtrueにする
			if ("entry".equals(localName)) {
				// Entry タグの開始
				isEntry = true;
			}

			//entryタグの中にいるか判定
			if (isEntry) {
				if ("id".equals(localName)) {
					isId = true;
				}
				if ("description".equals(localName)){
					isSummary = true;
				}
				// TODO 【SAX】 No.02 thumnailタグのurl属性を取得する
				if (!isThumbnail && "thumbnail".equals(localName)){
					thumbnail = attributes.getValue("url");
					isThumbnail = true;
				}
				if ("title".equals(localName)){
					isTitle = true;
				}
			}
		}

		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if ("entry".equals(localName)) {
				// TODO 【SAX】 No.03 rowModelに値を設定する 
				rowModel.setId(id);
				rowModel.setSummary(summary);
				rowModel.setThumbnailImageURL(thumbnail);
				rowModel.setTitle(title);

				//値をクリア
				id = null;
				summary = null;
				thumbnail = null;
				title = null;
				isThumbnail = false;
				isEntry = false;
			}
		}

		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			if (isEntry) {
				if (isId) {
					//idを取得する
					id = new String(ch, start, length);
					isId = false;
				}
				if (isSummary) {
					//descriptionを取得する
					summary = new String(ch, start, length);
					if (summary != null && 0 < summary.length()) {
						if (20 < length) {
							summary = summary.substring(0, 20);
						}
					}
					isSummary = false;
				}
				if (isTitle) {
					// TODO 【SAX】 No.04 titleを取得する
					title = new String(ch, start, length);
					isTitle = false;
				}
			}
		}
	}
	public RowModel parseXmlPullparser(Context context, String xml) {
		RowModel rowModel = null;
		InputStream is = null;
		try {
			// 解析対象のストリームを取得する
			is = context.getAssets().open("sample.xml");

			XmlPullParser parser = null;

			// TODO 【XMLPull】 No.01 XmlPullParserを定義する
			parser = Xml.newPullParser();
			// TODO 【XMLPull】 No.02  パースする文字列のストリームを渡す
			parser.setInput(new InputStreamReader(is));
			
			int eventType = 0;
			// XmlPullParser パースしている階層を取得
			final int depth = parser.getDepth();
			// XmlPullParser パースの終了条件
			/* TODO 【XMLPull】 No.03 while文で一つずつ処理をする */
			while( ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) || (parser.getDepth() > depth) ){
				// XmlPullParser eventTypeが開始タグか判定
				if (eventType == XmlPullParser.START_TAG) {
					// XmlPullParser タグの名前を取得する
					String tag = parser.getName();
					// XmlPullParser タグの名前が"entry"なら、parseToRowModelを呼び出す
					if ("entry".equals(tag)) {
						rowModel = parseToRowModel(parser);
						break;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return rowModel;
	}
	private RowModel parseToRowModel(XmlPullParser parser) throws XmlPullParserException, IOException {
		RowModel rowModel = new RowModel();
		int eventType;
		String tag = null;
		// パースする階層を取得する
		final int depth = parser.getDepth();
		// パースの終了条件
		while (((eventType = parser.next()) != XmlPullParser.END_DOCUMENT || parser
				.getDepth() > depth)) {
			// eventTypeが開始タグか判定
			if (eventType == XmlPullParser.START_TAG) {
				tag = parser.getName();
				// TODO 【XMLPull】 No.04  <entry>の中の<id>タグの値を取得し、RowModelに値をセットする
				if ("id".equals(tag)) {
					// 次に移動する。
					parser.next();
					// parserからテキスト情報を取得し、rowModelのURLにセットする。
					String id = parser.getText();
					rowModel.setId(id);

				} else if ("description".equals(tag)) {
					// 次に移動する。
					parser.next();
					// parserからテキスト情報を取得する。
					String summary = parser.getText();
					// 入りきらないので20文字でカットする。
					if (summary != null && 0 < summary.length()) {
						if (20 < summary.length()) {
							summary = summary.substring(0, 20);
						}
					}
					// rowModelのSUMMARYにセットする。
					rowModel.setSummary(summary);
				} else if ("thumbnail".equals(tag)) {
					// TODO 【XMLPull】 No.05  <thumbnail>から“url”属性の値を取得し、RowModelに値をセットするる
					if(rowModel.getThumbnailImageURL() == null){
						rowModel.setThumbnailImageURL(parser.getAttributeValue(null, "url"));
					}
					
				} else if ("title".equals(tag)) {
					// 次に移動する。
					parser.next();
					// parserからテキスト情報を取得し、rowModelのTitleにセットする。
					rowModel.setTitle(parser.getText());
				}
				// eventTypeが終了タグか判定
			} else if (eventType == XmlPullParser.END_TAG) {
				// タグの名前を取得する
				tag = parser.getName();
				// タグの名前が"entry"ならbreakする
				if ("entry".equals(tag)) {
					break;
				}
			}
		}
		return rowModel;
	}
}
